package com.system.service.imp;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.common.Enums.ResponseEnum;
import com.common.annotation.CacheExpire;
import com.common.exception.CourseException;
import com.common.util.CopyUtil;
import com.common.util.UuidUtil;
import com.core.system.domain.Dict;
import com.system.dto.DictDto;
import com.core.system.mapper.DictMapper;
import com.core.system.service.imp.DictServiceImp;
import com.system.dto.DtDictDto;
import com.system.service.DictService;
import com.system.util.MapperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Primary;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.common.Enums.ResponseEnum.ADD_SUCCESS;
import static com.common.Enums.ResponseEnum.UPD_SUCCESS;

@Service
@Primary
public class DictExServiceImp extends DictServiceImp implements DictService {
    @Autowired
    private DictMapper dictMapper;
    @Autowired
    private DictExServiceImp thisproxy;
    @Autowired
    private MapperUtils mapperUtils;

    @Override
    public ResponseEntity list(Page pageDto, com.core.system.domain.Dict dict) {
        IPage<Dict> page = dictMapper.selectPage(new Page<>(pageDto.getCurrent(), pageDto.getSize()),
                new LambdaQueryWrapper<Dict>(dict).orderBy(true, false, Dict::getCode));
        pageDto.setTotal(page.getTotal());
        List<DictDto> dictDtoList = CopyUtil.copyList(page.getRecords(), DictDto.class);
        pageDto.setRecords(dictDtoList);
        return ResponseEntity.ok(pageDto);
    }


    /**
     * 保存，id有值时更新，无值时新增
     */
    @Override
    @CacheEvict(cacheNames = "dict", key = "#dictDto.code")
    public ResponseEntity save(com.core.system.dto.DictDto dictDto) {
        Dict dict = CopyUtil.copy(dictDto, Dict.class);
        if (StringUtils.isEmpty(dictDto.getId())) {
            return this.insert(dict);
        } else {
            return this.update(dict);
        }
    }

    /**
     * 更新
     */
    private ResponseEntity update(Dict dict) {
        int i = dictMapper.updateById(dict);
        if (i <= 0) {
            throw new CourseException(ResponseEnum.UPDATE_ERROR);
        }
        return ResponseEntity.ok(UPD_SUCCESS.getDesc());
    }

    /**
     * 新增
     */
    private ResponseEntity insert(Dict dict) {
        dict.setId(UuidUtil.getmidUuid());
        int i = dictMapper.insert(dict);
        if (i <= 0) {
            throw new CourseException(ResponseEnum.ADD_ERROR);
        }
        return ResponseEntity.ok(ADD_SUCCESS.getDesc());
    }


    @Override
    public ResponseEntity loadTree(Dict dict) {
        List<Dict> dictList = dictMapper.selectList(
                new LambdaQueryWrapper<Dict>(ObjectUtils.isEmpty(dict) ? new Dict() : dict)
                        .orderBy(true, true, Dict::getSort));
        List<DictDto> dictDtoList = CopyUtil.copyList(dictList, DictDto.class);
        for (int i = dictDtoList.size() - 1; i >= 0; i--) {
            // 当前要移动的记录
            DictDto child = dictDtoList.get(i);
            // 如果当前节点没有父节点，则不用往下了
            if (StringUtils.isEmpty(child.getParentId())) {
                continue;
            }
            DictDto parent = null;
            // 查找父节点
            for (int j = dictDtoList.size() - 1; j >= 0; j--) {
                parent = dictDtoList.get(j);
                if (child.getParentId().equals(parent.getId())) {
                    if (CollectionUtils.isEmpty(parent.getChildren())) {
                        parent.setChildren(new ArrayList<>());
                    }
                    // 添加到最前面，否则会变成倒序，因为循环是从后往前循环的
                    if (!parent.getChildren().contains(child)) {
                        parent.getChildren().add(0, child);
                    }
                }
            }
            if (parent != null && parent.getChildren() != null && parent.getChildren().size() > 1) {
                List<DictDto> collect = parent.getChildren()
                        .stream()
                        .sorted((dict1, dict2) -> dict1.getSort().compareTo(dict2.getSort()))
                        .collect(Collectors.toList());
                parent.setChildren(collect);
            }
        }
        List<DictDto> dictDtoList1 = new ArrayList<>();
        for (int i = 0; i < dictDtoList.size(); i++) {
            if (StringUtils.isEmpty(dictDtoList.get(i).getParentId())) {
                dictDtoList1.add(dictDtoList.get(i));
            }
        }
        dictDtoList.clear();
        return ResponseEntity.ok(dictDtoList1);
    }

    @Override
    public ResponseEntity getDictValueBycode(String code) {
        List<DictDto> dictList = thisproxy.getDicts(code);
        return ResponseEntity.ok(dictList);
    }

    @Cacheable(cacheNames = "dict", key = "#code")
    @CacheExpire(expire = 30 * 60)
    public List<DictDto> getDicts(String code) {
        List<Dict> dictList = dictMapper.selectList(new LambdaQueryWrapper<Dict>().select(Dict::getDictKey, Dict::getDictValue, Dict::getIseffect, Dict::getListClass).eq(Dict::getCode, code).isNotNull(Dict::getParentId).orderBy(1 == 1, true, Dict::getSort));
        return CopyUtil.copyList(dictList, DictDto.class);
    }

    @Override
    public ResponseEntity getDtDict(DtDictDto dtDictDto) {
        List list = thisproxy.getdtDictList(dtDictDto);
        return ResponseEntity.ok(list);

    }

    public List getdtDictList(DtDictDto dtDictDto) {
        String mapperName = String.format("%sMapper", dtDictDto.getTable());
        BaseMapper baseMapper = mapperUtils.getMapper(mapperName);
        Class entiyClass = mapperUtils.getEntiyClass(mapperName);
        List list = new ArrayList<>();
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(entiyClass);
        String id = columnMap.get(LambdaUtils.formatKey(dtDictDto.getKey())).getColumn();
        String lable = columnMap.get(LambdaUtils.formatKey(dtDictDto.getLable())).getColumn();
        if (!ObjectUtils.isEmpty(baseMapper))
            list = baseMapper.selectList((Wrapper) new QueryWrapper().select(id, lable).in(id, dtDictDto.getIds()));
        return list;
    }

}
